package edu.amm.fanal.ui;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import edu.amm.fanal.api.BoundaryProblem;
import edu.amm.fanal.api.Coordinates.CoordinatesType;
import edu.amm.fanal.api.Function;
import edu.amm.fanal.api.NonlinearProblem;
import edu.amm.fanal.methods.GalerkinMethod;
import edu.amm.fanal.methods.MomentsMethod;
import edu.amm.fanal.methods.NewtonKantorovichMethod;

/**
 * @author Иванов Илья
 * @since 2013-05-16
 *
 */
public class OperatorEquation {
	
	private final int LEFT_BOUND = 0;
	private final int LEFT_VALUE = -1;
	private final int RIGHT_BOUND = 1;
	private final int RIGHT_VALUE = 0;
	
	private final Function F = new Function(NonlinearProblem.F_DIM) {
		
		private Function dfdt = new Function(getDim()) {
			
			protected double getValue(double... x) {
				return 0;
			}
		};
		
		private Function dfdx = new Function(getDim()) {
			
			protected double getValue(double... x) {
				return 0;
			}
		};
		
		private Function dfdxdt = new Function(getDim()) {
			
			protected double getValue(double... x) {
				return 3 * x[2] * Math.sqrt(x[2] * x[2] + 1);
			}
		};
		
		protected double getValue(double... x) {
			double val = x[2] * x[2] + 1;
			val = Math.sqrt(val);
			
			return val * val * val;
		}
		
		protected Function getDerivative(int variableNumber) {
			switch (variableNumber) {
				case 0:
					return dfdt;
				case 1:
					return dfdx;
				case 2:
					return dfdxdt;
				default:
					return null;
			}
		}
	};
	
	private final Function exactSolution = new Function(BoundaryProblem.SOLUTION_DIM) {
		
		protected double getValue(double... x) {
			double val = - Math.sqrt(1 - x[0] * x[0]);
			return val;
		}
	};
	
	private void solve() {
		NonlinearProblem problem = new NonlinearProblem(LEFT_BOUND, LEFT_VALUE, RIGHT_BOUND, RIGHT_VALUE);
		problem.setF(F);
		problem.setSolution(exactSolution);
		
		MomentsMethod momentsMethod = new GalerkinMethod(CoordinatesType.SINE);
		momentsMethod.setAccuracy(1e-5);
		
		NewtonKantorovichMethod kantorovich = new NewtonKantorovichMethod(momentsMethod);
		kantorovich.setIterationsCount(5);
		kantorovich.setInitialApproximation(new Function(BoundaryProblem.SOLUTION_DIM) {
			
			private Function derivative = new Function(getDim()) {
				
				protected double getValue(double... x) {
					return -1;
				}
			};
			
			protected double getValue(double... x) {
				return 1 - x[0];
			}
			
			protected Function getDerivative(int variableNumder) {
				return derivative;
			}
		});
		
		long start = System.currentTimeMillis();
		final Function solution = kantorovich.solve(problem);
		long finish = System.currentTimeMillis();
		
		log.info(String.format("Время вычислений: %d с", (finish - start) / 1000));
	}
	
	private static final String LOGGING_PROPERTIES = "edu/amm/fanal/logging.properties";
	
	public static void main(String[] args) {
		try {
			PropertyConfigurator.configure(OperatorEquation.class.getClassLoader().getResource(LOGGING_PROPERTIES));
		} catch (Throwable e) {
			System.err.println("Не удаётся сконфигурировать систему логирования");
			return;
		}
		
		new OperatorEquation().solve();
	}
	
	private static final Logger log = Logger.getLogger(OperatorEquation.class);
}